﻿using System;
using System.IO;
using System.Net;
using System.Text;
using RedBit.OAuthLibrary;
using TradeMeSDK.OAuthLibrary;

namespace TradeMeSDK
{
    public class TradeMeEventArgs : BaseEventArgs<string> {}

    public class WebHelper
    {
        public static void DownloadUrl(string url, Action<TradeMeEventArgs> callback)
        {
            HttpWebRequest request = WebRequest.CreateHttp(url);
            request.BeginGetResponse(asynchResult =>
            {
                HttpWebResponse response = null;
                try
                {
                    response = (HttpWebResponse)request.EndGetResponse(asynchResult);
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        using (StreamReader sr = new StreamReader(response.GetResponseStream()))
                        {
                            var token = sr.ReadToEnd();
                            TradeMeDispatcher.OnUIThread(() => callback(new TradeMeEventArgs { Response = token }));
                        }
                    }
                }
                catch (WebException we)
                {
                    //string t = new StreamReader(we.Response.GetResponseStream()).ReadToEnd();
                    TradeMeDispatcher.OnUIThread(() => callback(new TradeMeEventArgs { Error = we, ErrorMessage = we.Message }));
                }
                catch (Exception ex)
                {
                    TradeMeDispatcher.OnUIThread(() => callback(new TradeMeEventArgs { Error = ex, ErrorMessage = "Error downloading information" }));
                }
                finally
                {
                    if (response != null)
                        response.Close();
                }
            }, null);
        }

        /// <summary>
        /// Download and parse a trademe resource.  If you supply just the path, then the BASE URI will be prepended
        /// e.g. http://api.trademe.co.nz/v1/Listings/313077245.xml
        /// or /v1/Listings/313077245.xml  will achieve the same result.
        /// </summary>
        public static void DownloadAndParse<T>(string url, Action<BaseEventArgs<T>> callback) where T : class
        {
            if (!url.ToLower().StartsWith("http"))
            {
                var uri = new Uri(TradeMeRepository.BaseUri, url);
                url = uri.AbsoluteUri;
            }

            DownloadUrl(url, args =>
            {
                if (args.IsError)
                {
                    TradeMeDispatcher.OnUIThread(() =>
                        callback(new BaseEventArgs<T> { Error = args.Error, ErrorMessage = args.ErrorMessage }));
                    return;
                }

                T response = JsonParser.Parse<T>(args.Response);
                if (response == null)
                {
                    TradeMeDispatcher.OnUIThread(() =>
                        callback(new BaseEventArgs<T>
                        {
                            IsError = true,
                            ErrorMessage = "Unable to parse response"
                        }));
                    return;
                }

                TradeMeDispatcher.OnUIThread(() =>
                    callback(new BaseEventArgs<T> { Response = response }));
            });

        }

        public static void DownloadAndParseProtected<T>(string url, Action<BaseEventArgs<T>> callback) where T : class
        {
            if (!url.ToLower().StartsWith("https"))
            {
                var uri = new Uri(TradeMeRepository.BaseSecureUri, url);
                url = uri.AbsoluteUri;
            }

            OAuth.GetProtectedResource(url, "GET",
                                       TradeMeOAuth.ConsumerKey,
                                       TradeMeOAuth.ConsumerSecret,
                                       TradeMeOAuth.Token,
                                       TradeMeOAuth.TokenSecret, (obj, args) =>
                                       {
                                           if (args.IsError)
                                           {
                                               TradeMeDispatcher.OnUIThread(() =>
                                                   callback(new BaseEventArgs<T> { Error = args.Error, ErrorMessage = args.ErrorMessage }));
                                               return;
                                           }

                                           T response = JsonParser.Parse<T>(args.Response);
                                           if (response == null)
                                           {
                                               TradeMeDispatcher.OnUIThread(() =>
                                                   callback(new BaseEventArgs<T>
                                                   {
                                                       IsError = true,
                                                       ErrorMessage = "Unable to parse response"
                                                   }));
                                               return;
                                           }

                                           TradeMeDispatcher.OnUIThread(() =>
                                               callback(new BaseEventArgs<T> { Response = response }));
                                       });
        }

        public static void PostAndParseProtected<T>(string url, string content, Action<BaseEventArgs<T>> callback) where T : class
        {
            if (!url.ToLower().StartsWith("https"))
            {
                var uri = new Uri(TradeMeRepository.BaseSecureUri, url);
                url = uri.AbsoluteUri;
            }

            OAuth.PostProtectedResource(url, content, "text/xml",
                                       TradeMeOAuth.ConsumerKey,
                                       TradeMeOAuth.ConsumerSecret,
                                       TradeMeOAuth.Token,
                                       TradeMeOAuth.TokenSecret, (obj, args) =>
                                       {
                                           if (args.IsError)
                                           {
                                               TradeMeDispatcher.OnUIThread(() =>
                                                   callback(new BaseEventArgs<T> { Error = args.Error, ErrorMessage = args.ErrorMessage }));
                                               return;
                                           }

                                           T response = JsonParser.Parse<T>(args.Response);
                                           if (response == null)
                                           {
                                               TradeMeDispatcher.OnUIThread(() =>
                                                   callback(new BaseEventArgs<T>
                                                   {
                                                       IsError = true,
                                                       ErrorMessage = "Unable to parse response"
                                                   }));
                                               return;
                                           }

                                           TradeMeDispatcher.OnUIThread(() =>
                                               callback(new BaseEventArgs<T> { Response = response }));
                                       });

        }


        public static void AddParameter(string parameterName, string value, StringBuilder query)
        {
            if (string.IsNullOrEmpty(value)) return;

            if (query.Length > 0)
                query.Append('&');
            query.Append(parameterName + "=" + value);
        }

        public static void AddParameter(string parameterName, int value, StringBuilder query)
        {
            if (value == 0) return;
            AddParameter(parameterName, value.ToString(), query);
        }

        public static void AddParameter(string parameterName, decimal value, StringBuilder query)
        {
            if (value == 0) return;
            AddParameter(parameterName, value.ToString(), query);
        }

        public static void AddParameter(string parameterName, bool value, StringBuilder query)
        {
            if (value)
                AddParameter(parameterName, "true", query);
        }
    }
}
